Micron Document
🎖️GitЯра🎖️

Node / meshtastic / Meshtastic-Android / files / app / src / main / java / com / geeksville / mesh / repository / bluetooth / BluetoothRepository.kt

Displaying Raw • Download

app/src/main/java/com/geeksville/mesh/repository/bluetooth/BluetoothRepository.kt 78274c792318331b11ab64cd28e58e829875b8c2 (78274c79) Text, 7.13 KB

T8b949e/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

Tff7b72package T7ee787com.geeksville.mesh.repository.bluetooth

Tff7b72import T7ee787android.annotation.SuppressLint
Tff7b72import T7ee787android.app.Application
Tff7b72import T7ee787android.bluetooth.BluetoothAdapter
Tff7b72import T7ee787androidx.lifecycle.Lifecycle
Tff7b72import T7ee787androidx.lifecycle.coroutineScope
Tff7b72import T7ee787com.geeksville.mesh.repository.radio.BleConstants.BLE_NAME_PATTERN
Tff7b72import T7ee787com.geeksville.mesh.repository.radio.BleConstants.BTM_SERVICE_UUID
Tff7b72import T7ee787com.geeksville.mesh.util.registerReceiverCompat
Tff7b72import T7ee787dagger.Lazy
Tff7b72import T7ee787kotlinx.coroutines.Job
Tff7b72import T7ee787kotlinx.coroutines.flow.MutableStateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.StateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.asStateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.catch
Tff7b72import T7ee787kotlinx.coroutines.flow.map
Tff7b72import T7ee787kotlinx.coroutines.flow.onCompletion
Tff7b72import T7ee787kotlinx.coroutines.flow.onStart
Tff7b72import T7ee787kotlinx.coroutines.launch
Tff7b72import T7ee787no.nordicsemi.kotlin.ble.client.android.CentralManager
Tff7b72import T7ee787no.nordicsemi.kotlin.ble.client.android.Peripheral
Tff7b72import T7ee787no.nordicsemi.kotlin.ble.client.distinctByPeripheral
Tff7b72import T7ee787no.nordicsemi.kotlin.ble.core.Manager
Tff7b72import T7ee787org.meshtastic.core.common.hasBluetoothPermission
Tff7b72import T7ee787org.meshtastic.core.di.CoroutineDispatchers
Tff7b72import T7ee787timber.log.Timber
Tff7b72import T7ee787javax.inject.Inject
Tff7b72import T7ee787javax.inject.Singleton
Tff7b72import T7ee787kotlin.time.Duration.Companion.seconds
Tff7b72import T7ee787kotlin.uuid.ExperimentalUuidApi
Tff7b72import T7ee787kotlin.uuid.toKotlinUuid

T8b949e/** Repository responsible for maintaining and updating the state of Bluetooth availability. */
Tf0883e@Singleton
Tff7b72class T56d364BluetoothRepository
Tf0883e@Inject
Tff7b72constructorTb4b4b4(
Tff7b72private Tff7b72val Te6edf3applicationTb4b4b4: Te6edf3ApplicationTb4b4b4,
Tff7b72private Tff7b72val Te6edf3bluetoothBroadcastReceiverLazyTb4b4b4: Te6edf3LazyTff7b72<Te6edf3BluetoothBroadcastReceiverTff7b72>Tb4b4b4,
Tff7b72private Tff7b72val Te6edf3dispatchersTb4b4b4: Te6edf3CoroutineDispatchersTb4b4b4,
Tff7b72private Tff7b72val Te6edf3processLifecycleTb4b4b4: Te6edf3LifecycleTb4b4b4,
Tff7b72private Tff7b72val Te6edf3centralManagerTb4b4b4: Te6edf3CentralManagerTb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3_state Tff7b72=
Te6edf3MutableStateFlowTb4b4b4(
Te6edf3BluetoothStateTb4b4b4(
T8b949e// Assume we have permission until we get our initial state update to prevent premature
T8b949e// notifications to the user.
Te6edf3hasPermissions Tff7b72= Tff7b72trueTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3stateTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3BluetoothStateTff7b72> Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)

Tff7b72private Tff7b72val Te6edf3_scannedDevices Tff7b72= Te6edf3MutableStateFlowTff7b72<Te6edf3ListTff7b72<Te6edf3PeripheralTff7b72>Tff7b72>Tb4b4b4(Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3scannedDevicesTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3ListTff7b72<Te6edf3PeripheralTff7b72>Tff7b72> Tff7b72= Te6edf3_scannedDevicesTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)

Tff7b72private Tff7b72val Te6edf3_isScanning Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Tff7b72falseTb4b4b4)
Tff7b72val Te6edf3isScanningTb4b4b4: Te6edf3StateFlowTff7b72<Tffa657BooleanTff7b72> Tff7b72= Te6edf3_isScanningTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)

Tff7b72private Tff7b72var Te6edf3scanJobTb4b4b4: Te6edf3Job? Tff7b72= Tff7b72null

Tff7b72init Tb4b4b4{
Te6edf3processLifecycleTb4b4b4.Te6edf3coroutineScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3defaultTb4b4b4) Tb4b4b4{
Te6edf3updateBluetoothStateTb4b4b4(Tb4b4b4)
Te6edf3bluetoothBroadcastReceiverLazyTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3let Tb4b4b4{ Te6edf3receiver Tff7b72-Tff7b72>
Te6edf3applicationTb4b4b4.Te6edf3registerReceiverCompatTb4b4b4(Te6edf3receiverTb4b4b4, Te6edf3receiverTb4b4b4.Te6edf3intentFilterTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72fun Td2a8ffrefreshStateTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3processLifecycleTb4b4b4.Te6edf3coroutineScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3defaultTb4b4b4) Tb4b4b4{ Te6edf3updateBluetoothStateTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4}

T8b949e/** @return true for a valid Bluetooth address, false otherwise */
Tff7b72fun Td2a8ffisValidTb4b4b4(Te6edf3bleAddressTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3BluetoothAdapterTb4b4b4.Te6edf3checkBluetoothAddressTb4b4b4(Te6edf3bleAddressTb4b4b4)

T8b949e/** Starts a BLE scan for Meshtastic devices. The results are published to the [scannedDevices] flow. */
Tf0883e@OptInTb4b4b4(Te6edf3ExperimentalUuidApiTff7b72::Te6edf3classTb4b4b4)
Tf0883e@SuppressLintTb4b4b4(Ta5d6ff"Ta5d6ffMissingPermissionTa5d6ff"Tb4b4b4)
Tff7b72fun Td2a8ffstartScanTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3isScanningTb4b4b4.Te6edf3valueTb4b4b4) Tff7b72return

Te6edf3scanJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3_scannedDevicesTb4b4b4.Te6edf3value Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)

Te6edf3scanJob Tff7b72=
Te6edf3processLifecycleTb4b4b4.Te6edf3coroutineScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3defaultTb4b4b4) Tb4b4b4{
Te6edf3centralManager
Tb4b4b4.Te6edf3scanTb4b4b4(T79c0ff5.Te6edf3secondsTb4b4b4) Tb4b4b4{ Te6edf3ServiceUuidTb4b4b4(Te6edf3BTM_SERVICE_UUIDTb4b4b4.Te6edf3toKotlinUuidTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3distinctByPeripheralTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3peripheral Tb4b4b4}
Tb4b4b4.Te6edf3onStart Tb4b4b4{ Te6edf3_isScanningTb4b4b4.Te6edf3value Tff7b72= Tff7b72true Tb4b4b4}
Tb4b4b4.Te6edf3onCompletion Tb4b4b4{ Te6edf3_isScanningTb4b4b4.Te6edf3value Tff7b72= Tff7b72false Tb4b4b4}
Tb4b4b4.Te6edf3catch Tb4b4b4{ Te6edf3ex Tff7b72-Tff7b72>
Te6edf3TimberTb4b4b4.Te6edf3wTb4b4b4(Te6edf3exTb4b4b4, Ta5d6ff"Ta5d6ffBluetooth scan failedTa5d6ff"Tb4b4b4)
Te6edf3_isScanningTb4b4b4.Te6edf3value Tff7b72= Tff7b72false
Tb4b4b4}
Tb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3peripheral Tff7b72-Tff7b72>
T8b949e// Add or update the peripheral in our list
Tff7b72val Te6edf3currentList Tff7b72= Te6edf3_scannedDevicesTb4b4b4.Te6edf3value
Te6edf3_scannedDevicesTb4b4b4.Te6edf3value Tff7b72=
Tb4b4b4(Te6edf3currentListTb4b4b4.Te6edf3filterNot Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3address Tff7b72=Tff7b72= Te6edf3peripheralTb4b4b4.Te6edf3address Tb4b4b4} Tff7b72+ Te6edf3peripheralTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e/** Stops the currently active BLE scan. */
Tff7b72fun Td2a8ffstopScanTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3scanJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3scanJob Tff7b72= Tff7b72null
Te6edf3_isScanningTb4b4b4.Te6edf3value Tff7b72= Tff7b72false
Tb4b4b4}

T8b949e/**
* Initiates bonding with the given peripheral. This is a suspending function that completes when the bonding
* process is finished. After successful bonding, the repository's state is refreshed to include the new bonded
* device.
*
* @param peripheral The peripheral to bond with.
* @throws SecurityException if required Bluetooth permissions are not granted.
* @throws Exception if the bonding process fails.
*/
Tf0883e@SuppressLintTb4b4b4(Ta5d6ff"Ta5d6ffMissingPermissionTa5d6ff"Tb4b4b4)
Tff7b72suspend Tff7b72fun Td2a8ffbondTb4b4b4(Te6edf3peripheralTb4b4b4: Te6edf3PeripheralTb4b4b4) Tb4b4b4{
Te6edf3peripheralTb4b4b4.Te6edf3createBondTb4b4b4(Tb4b4b4)
Te6edf3refreshStateTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tf0883e@OptInTb4b4b4(Te6edf3ExperimentalUuidApiTff7b72::Te6edf3classTb4b4b4)
Tff7b72internal Tff7b72suspend Tff7b72fun Td2a8ffupdateBluetoothStateTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3hasPerms Tff7b72= Te6edf3applicationTb4b4b4.Te6edf3hasBluetoothPermissionTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3enabled Tff7b72= Te6edf3centralManagerTb4b4b4.Te6edf3stateTb4b4b4.Te6edf3value Tff7b72=Tff7b72= Te6edf3ManagerTb4b4b4.Te6edf3StateTb4b4b4.Te6edf3POWERED_ON
Tff7b72val Te6edf3newState Tff7b72=
Te6edf3BluetoothStateTb4b4b4(
Te6edf3hasPermissions Tff7b72= Te6edf3hasPermsTb4b4b4,
Te6edf3enabled Tff7b72= Te6edf3enabledTb4b4b4,
Te6edf3bondedDevices Tff7b72= Te6edf3getBondedAppPeripheralsTb4b4b4(Te6edf3enabledTb4b4b4)Tb4b4b4,
Tb4b4b4)

Te6edf3_stateTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3newStateTb4b4b4)
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffDetected our bluetooth access=Tffd700$Te6edf3newStateTa5d6ff"Tb4b4b4)
Tb4b4b4}

Tf0883e@SuppressLintTb4b4b4(Ta5d6ff"Ta5d6ffMissingPermissionTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffgetBondedAppPeripheralsTb4b4b4(Te6edf3enabledTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Te6edf3PeripheralTff7b72> Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3enabled Tff7b72&Tff7b72& Te6edf3applicationTb4b4b4.Te6edf3hasBluetoothPermissionTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3centralManagerTb4b4b4.Te6edf3getBondedPeripheralsTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3filterTb4b4b4(Tff7b72::Te6edf3isMatchingPeripheralTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3emptyListTb4b4b4(Tb4b4b4)
Tb4b4b4}

T8b949e/** Checks if a peripheral is one of ours, either by its advertised name or by the services it provides. */
Tf0883e@OptInTb4b4b4(Te6edf3ExperimentalUuidApiTff7b72::Te6edf3classTb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffisMatchingPeripheralTb4b4b4(Te6edf3peripheralTb4b4b4: Te6edf3PeripheralTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3nameMatches Tff7b72= Te6edf3peripheralTb4b4b4.Te6edf3nameTff7b72?.Te6edf3matchesTb4b4b4(Te6edf3RegexTb4b4b4(Te6edf3BLE_NAME_PATTERNTb4b4b4)Tb4b4b4) Tff7b72?: Tff7b72false
Tff7b72val Te6edf3hasRequiredService Tff7b72=
Te6edf3peripheralTb4b4b4.Te6edf3servicesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3BTM_SERVICE_UUIDTb4b4b4.Te6edf3toKotlinUuidTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3valueTff7b72?.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72false

Tff7b72return Te6edf3nameMatches Tff7b72|Tff7b72| Te6edf3hasRequiredService
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.06s